package pdf

import (
	"fmt"
	"gitee.com/851537/gbase"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/google/uuid"
	"github.com/pdfcpu/pdfcpu/pkg/api"
	"os"
	"os/exec"
	"runtime"
)

type File struct {

	//路径必须为短路径，各方法处理文件前转为长路径
	Path gbase.Filepath
}

func (this *File) WithPath(path gbase.Filepath) *File {
	this.Path = path
	return this
}

//func (this *File) GenFromTxt(txt string) (err error) {
//	mediaBox := types.RectForFormat("A4")
//	p := model.Page{MediaBox: mediaBox, Fm: model.FontMap{}, Buf: new(bytes.Buffer)}
//	pdfcpu.CreateTestPageContent(p)
//	xRefTable, err := pdfcpu.CreateDemoXRef()
//	if err != nil {
//		return
//	}
//	rootDict, err := xRefTable.Catalog()
//	if err != nil {
//		return
//	}
//	if err = pdfcpu.AddPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil {
//		return
//	}
//	//createAndValidate(t, xRefTable, "Test.pdf", msg)
//	//outDir := "../../samples/basic"
//	//outFile = filepath.Join(outDir, outFile)
//	outFile := this.Path.WrapLong().ToString()
//	if err = api.CreatePDFFile(xRefTable, outFile, nil); err != nil {
//		return err
//	}
//	return api.ValidateFile(outFile, nil)
//}

// use wkhtmltopdf
func (this *File) GenFromHtml(html string) (file *File, err error) {

	var (
		htmlFile gbase.Filepath
	)
	htmlFile = gbase.Filepath(fmt.Sprintf("/rumtime/html/%s.html", uuid.NewString()))
	if err = htmlFile.WrapLong().SaveContent(html); err != nil {
		return nil, err
	}
	defer htmlFile.WrapLong().Rm()

	//gen pdf by wkhtmltopdf-------------------
	args := make([]string, 0)
	//打印纸尺寸
	args = append(args, "--page-size", "A4")   //default A4
	args = append(args, "--encoding", "UTF-8") //

	//下面这个不起作用：
	//如果 --margin-bottom 选项在 wkhtmltopdf 中不起作用，可能是由于几个原因：
	//HTML/CSS样式覆盖：页面的HTML或CSS样式可能覆盖了 wkhtmltopdf 的边距设置。检查你的HTML和CSS文件，确保没有样式会强制内容填满整个页面或覆盖边距设置。
	//命令格式问题：确保你正确地使用了命令行参数。检查是否有任何拼写错误或格式问题。
	//版本问题：确保你使用的 wkhtmltopdf 是最新版本或至少是一个支持该功能的版本。
	//命令行参数冲突：检查是否使用了其他可能与 --margin-bottom 冲突的参数。
	//如果问题仍然存在，建议查阅 wkhtmltopdf 的官方文档或社区论坛，看看是否有类似的问题和解决方案。在某些情况下，可能需要结合HTML/CSS调整和命令行参数调优来达到预期效果。
	args = append(args, "--margin-bottom", "15mm") //

	//args = append(args, "--javascript-delay", "2000") //

	//页眉
	//if headFileName, err := this.GenHeadFile(); err == nil {
	//	args = append(args, "--header-html", runtimePath(headFileName))
	//	args = append(args, "--header-line")
	//	defer os.Remove(runtimePath(headFileName))
	//}
	//
	////footer
	//args = append(args, "--footer-line")
	//args = append(args, "--footer-html", tplPath("footer.html"))

	_ = this.Path.WrapLong().MkDir()
	args = append(args, htmlFile.WrapLong().ToString(), this.Path.WrapLong().ToString()) // "xx.html" "output.pdf"

	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		cmd = exec.Command("D:/wkhtmltopdf/bin/wkhtmltopdf", args...) //for windows
	} else {
		cmd = exec.Command("wkhtmltopdf", args...) //for linux
	}

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	// 执行命令
	if err = cmd.Run(); err != nil {
		hlog.Errorf("execute cmd failed,err:%s,cmd:%s", err.Error(), cmd.String())
		return this, err
	}

	//D:/wkhtmltopdf/bin/wkhtmltopdf.exe --page-size A4 --encoding UTF-8 --margin-bottom 15mm 1828244237477482496.html 14215_tax.pdf
	//add footer with dictum
	//if filePath, err = this.AddFooter(filePath); err != nil {
	//	hlog.Errorf("GenPdfV2 addFooter failed,err:%s", err.Error())
	//	return
	//}
	return this, nil
}

func (this *File) GenFromImgs(imgPaths ...string) (err error) {
	return api.ImportImagesFile(imgPaths, this.Path.ToString(), nil, nil)
}

func (this *File) GetPageNum() (pageNum int, err error) {
	return api.PageCountFile(this.Path.ToString())
}

// 是否纵向，取第一页判断
func (this *File) IsPortrait() bool {
	if dims, err := api.PageDimsFile(this.Path.ToString()); err != nil || len(dims) == 0 {
		return false
	} else {
		return dims[0].Portrait()
	}
}

//var pdf2pngMu sync.Mutex
//
//func (this *File) Pdf2Png(distDir globalbase.CFilePath, dpi int, firstPage ...bool) (firstPngPath globalbase.CFilePath, err error) {
//	var (
//		cmd         *exec.Cmd
//		isFirstPage = len(firstPage) > 0 && firstPage[0]
//		//filename    = this.Path.GetFileNameWithoutExt()
//	)
//	pdf2pngMu.Lock()
//	defer pdf2pngMu.Unlock()
//
//	if dpi == 0 {
//		dpi = 30
//	}
//
//	//pngPath = globalbase.CFilePath(fmt.Sprintf("%s/%s", distDir, filename))
//	pngPathWithoutExt := fmt.Sprintf("%s/%s", distDir, this.Path.GetFileNameWithoutExt())
//	if err = globalbase.CFilePath(pngPathWithoutExt).MkDir(); err != nil {
//		return
//	}
//
//	args := make([]string, 0)
//	args = append(args, "-r", fmt.Sprintf("%d", dpi))
//	//if isFirstPage {
//	//	args = append(args, "-f", "1")
//	//	args = append(args, "-l", "1")
//	//}
//
//	//todo 改成并发处理
//	if runtime.GOOS == "windows" {
//		if isFirstPage {
//			args = append(args, "-f", "1")
//			args = append(args, "-l", "1")
//		}
//		//args = append(args, "-r", "15")
//		args = append(args, "-alpha")
//		args = append(args, this.Path.ToString(), pngPathWithoutExt)
//		cmd = exec.Command("./3rdtools/xpdfreader/pdftopng.exe", args...)
//
//		hlog.Debugf("cmd:%s", cmd.String())
//
//		//这里没有测试过，可能文件名对不上
//		firstPngPath = globalbase.CFilePath(fmt.Sprintf("%s-001.png", pngPathWithoutExt))
//		//ori
//		//cmd = exec.Command("./3rdtools/xpdfreader/pdftopng.exe", "-alpha", this.Path.ToString(), fmt.Sprintf("./%s%s", distDir, "pdf"))
//	} else {
//		if isFirstPage {
//			args = append(args, "-singlefile")
//		}
//		args = append(args, "-png")
//		args = append(args, this.Path.ToString(), pngPathWithoutExt) //fmt.Sprintf("%s%s", distDir, filename)
//		cmd = exec.Command("pdftoppm", args...)
//
//		hlog.Debugf("cmd:%s", cmd.String())
//		firstPngPath = globalbase.CFilePath(fmt.Sprintf("%s.png", pngPathWithoutExt))
//
//		//ori
//		//pdftoppm -r 15 -png pdf文件.pdf pdfpng  //按15DPI转换，加快速度
//		//cmd = exec.Command("pdftoppm", "-r", "15", "-png", this.Path.ToString(), fmt.Sprintf("./%s%s", distDir, "pdf"))
//	}
//	t := globalbase.NewTime()
//	hlog.Debugf("start Pdf2Png")
//	if err = cmd.Run(); err != nil {
//		hlog.Debugf("pdf.File.Pdf2Png Pdf2Png failed,err:%s", err.Error())
//		return
//	}
//	hlog.Debugf("end Pdf2Png,dur:%d", globalbase.NewTime().DiffSec(t))
//
//	return
//}
//
//// 计算pdf文件非空白覆盖率,需要xpdfReader库支持,放到bin目录下
//func (this *File) CalPrintRatio() (totalRatio float64, err error) {
//	var (
//		tmpDir globalbase.CFilePath
//		ratios []float64
//		//cmd    *exec.Cmd
//	)
//	tmpDir = globalbase.CFilePath(fmt.Sprintf("/runtime/pdfPrintRatio/%d", global.IdNode.Generate().Int64()))
//	if err = tmpDir.WrapLong().MkDir(); err != nil {
//		return 0, errors.New("创建临时目录失败")
//	}
//	defer func() {
//		if err = tmpDir.WrapLong().RmDir(); err != nil {
//			hlog.Debugf("CalPrintRatio 删除临时目录失败,err:%s", err.Error())
//		}
//	}()
//
//	////todo 改成并发处理
//	//if runtime.GOOS == "windows" {
//	//	cmd = exec.Command("./3rdtools/xpdfreader/pdftopng.exe", "-alpha", this.Path.ToString(), fmt.Sprintf("./%s%s", tmpDir.WrapLong(), "pdf"))
//	//} else {
//	//	//pdftoppm -png pdf文件.pdf pdfpng
//	//	cmd = exec.Command("pdftoppm", "-png", this.Path.ToString(), fmt.Sprintf("./%s%s", tmpDir.WrapLong(), "pdf"))
//	//}
//	//if err = cmd.Run(); err != nil {
//	//	return 0, err
//	//}
//
//	if _, err = this.Pdf2Png(tmpDir.WrapLong(), 0); err != nil {
//		hlog.Debugf("CalPrintRatio Pdf2Png failed,err:%s", err.Error())
//		return 0, err
//	}
//
//	//计算覆盖率
//	ratios = make([]float64, 0)
//	err = tmpDir.WrapLong().DirWalk(func(path string, info fs.FileInfo, err error) error {
//		t := globalbase.NewTime()
//		if err == nil && !info.IsDir() {
//			fmt.Printf("File: %s\n", path)
//
//			//todo mv fun
//			var (
//				totalPoint int64
//				printPoint int64
//			)
//
//			// 打开源图片文件
//			srcFile, err := os.Open(path)
//			if err != nil {
//				return err
//			}
//			defer srcFile.Close()
//			srcImage, _, err := image.Decode(srcFile)
//			if err != nil {
//				hlog.Errorf("decode src img failed,err:%s", err.Error())
//				return err
//			}
//			for y := srcImage.Bounds().Min.Y; y < srcImage.Bounds().Max.Y; y++ {
//				for x := srcImage.Bounds().Min.X; x < srcImage.Bounds().Max.X; x++ {
//					// 获取像素点的 RGBA 值
//					r, g, b, a := srcImage.At(x, y).RGBA()
//					totalPoint++
//					// 判断是否透明
//					if a == 0 {
//						//hlog.Debugf("像素点 (%d, %d) 是透明的\n", x, y)
//					} else if r == 0xffff && g == 0xffff && b == 0xffff {
//						//hlog.Debugf("像素点 (%d, %d) 是纯白色的\n", x, y)
//					} else {
//						//hlog.Debugf("像素点 (%d, %d) 是其它色\n", x, y)
//						printPoint++
//					}
//				}
//			}
//			hlog.Debugf("覆盖率：%.2f%%", float64(printPoint)*100/float64(totalPoint))
//			hlog.Debugf("CalPrintRatio cal printRatio,dur:%d", globalbase.NewTime().DiffSec(t))
//			ratios = append(ratios, float64(printPoint)*100/float64(totalPoint))
//		}
//		return nil
//	})
//	if err != nil {
//		//hlog
//		return 0, errors.New("计算出错")
//	}
//	for _, v := range ratios {
//		totalRatio += v
//	}
//	totalRatio = totalRatio / float64(len(ratios))
//	return
//}

func (this *File) Merger(outFileName string, files ...*File) (outFile *File, err error) {
	inFiles := make([]string, 0)
	inFiles = append(inFiles, this.Path.ToString())
	for _, v := range files {
		inFiles = append(inFiles, v.Path.ToString())
	}
	if outFileName == "" {
		outFileName = fmt.Sprintf("%s_合并", this.Path.GetFileNameWithoutExt())
	}
	outFile = NewFile().WithPath(this.Path.ModFileNameWithExt(outFileName, ".pdf"))
	if err = api.MergeCreateFile(inFiles, outFile.Path.ToString(), false, nil); err != nil {
		return
	}
	return
}

// 在最后一页追加加一个空白页
func (this *File) AppendBlankPage() (err error) {
	var (
		pageNum int
	)
	if pageNum, err = this.GetPageNum(); err != nil {
		return
	}
	return api.InsertPagesFile(this.Path.ToString(), "", []string{fmt.Sprintf("%d", pageNum)}, false, nil, nil)
}

// 添加水印
// opt := "scale:1, pos:bl, off:0 0, rot:0, op:.5"
// err := file.AddWaterMark(globalbase.CFilePath("static/contract/wm.png"), opt)
func (this *File) AddWaterMark(waterFile gbase.Filepath, opt string) (err error) {
	// 水印配置
	//tmpFile := this.Path.ModFileName(global.IdNode.Generate().String())
	err = api.AddImageWatermarksFile(
		this.Path.WrapLong().ToString(),
		this.Path.WrapLong().ToString(),
		nil, true, waterFile.ToString(), opt, nil)

	return

	//return api.AddTextWatermarksFile(
	//	this.Path.ToString(),
	//	this.Path.ModFileName("x").ToString(),
	//	nil, true, "格林美", "fo:Courier, scale:.9, fillcol:#00aacc, op:.6", nil)
}

// path路径必须为短路径，各方法处理文件前转为长路径
func NewFile(path ...gbase.Filepath) (file *File) {
	if len(path) > 0 {
		file = &File{Path: path[0]}
	} else {
		file = &File{}
	}
	return
}
